package com.kevin.table;

import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;

import com.kevin.enums.DBType;
import com.kevin.sql.DataType;
public class MDataColumn implements List<MCellStruct> {
	/**
	 * 存储列名的索引
	 */
	private Map<String, Integer> columnIndex = new ConcurrentHashMap<>();
	/**
	 * 列名是否变更
	 */
	boolean isColumnNameChanged = false;
	
	/**
	 * 添加列时，检测名称是否重复(默认为true)。
	 */
	public boolean checkDuplicate = true;
	
	/**
	 * 当前的数据库类型。
	 */
	DBType dbType = DBType.NONE;
	
	/**
	 * 该结构是否由视图拥有
	 */
	boolean isViewOwner = false;
	ArrayList<String> relationTables = new ArrayList<>();
	
    void AddRelateionTableName(String tableName)
    {
        if (!StringUtils.isEmpty(tableName) && !relationTables.contains(tableName))
        {
            relationTables.add(tableName);
        }
    }
	
	ArrayList<MCellStruct> structList;
	
	private MDataTable table;

	public MDataColumn(){
		structList = new ArrayList<MCellStruct>();
	}
	
	MDataColumn(MDataTable dt){
		structList = new ArrayList<MCellStruct>();
		table = dt;
	}
	
	/**
	 * 架构所引用的表(只读属性)
	 * @return
	 */
//	public MDataTable getTable() {
//		return table;
//	}

	private ArrayList<MCellStruct> jointPrimary = new ArrayList<>();
	
	public ArrayList<MCellStruct> getJointPrimary() {
		MCellStruct autoIncrementCell = null;
		if (jointPrimary.size() == 0 && this.size() > 0)
        {
            for (MCellStruct item : this)
            {
                if (item.isPrimaryKey())
                {
                	jointPrimary.add(item);
                }
                else if (item.isAutoIncrement())
                {
                    autoIncrementCell = item;
                }
            }
            if (jointPrimary.size() == 0)
            {
                if (autoIncrementCell != null)
                {
                	jointPrimary.add(autoIncrementCell);
                }
                else
                {
                	jointPrimary.add(this.get(0));
                }
            }
        }
        return jointPrimary;
	}
	
	public MCellStruct getFirstPrimary(){
        if (getJointPrimary().size() > 0)
        {
            return getJointPrimary().get(0);
        }
        return null;
	}
	
	public MDataRow toRow(String tableName)
    {
        MDataRow row = new MDataRow(this);
        row.setTableName(tableName);
        row.getColumns().checkDuplicate = checkDuplicate;      
        row.getColumns().dbType = dbType;
        row.getColumns().isViewOwner = isViewOwner;
        row.getColumns().relationTables = relationTables;
        return row;
    }
	
	public boolean addRange(MDataColumn dcol){
		if(dcol.size() > 0){
			for(MCellStruct cs:dcol){
				if(!contains(cs.getColumnName())){
					add(cs);
				}
			}
			
		}
		return true;
	}
	
	/**
	 * 首个唯一键
	 * @return
	 */
	public MCellStruct getFirstUnique(){
        MCellStruct ms = null;
        for (MCellStruct item : this)
        {
            if (item.isUniqueKey())
            {
                return item;
            }
            else if (ms == null && !item.isPrimaryKey() && DataType.getGroup(item.getSqlType()) == 0)//取第一个字符串类型
            {
                ms = item;
            }
        }
        if (ms == null && this.size() > 0)
        {
            ms = this.get(0);
        }
        return ms;
	}
	
    public void setDbType(DBType dbType) {
		this.dbType = dbType;
	}

	public DBType getDbType() {
		return dbType;
	}

	public MDataColumn clone()
    {
        MDataColumn mcs = new MDataColumn();
        mcs.dbType = dbType;
        mcs.checkDuplicate = false;
        mcs.isViewOwner = isViewOwner;
        for (String item : relationTables)
        {
            mcs.AddRelateionTableName(item);
        }
        for (int i = 0; i < this.size(); i++)
        {
            mcs.add(this.get(i).clone());
        }
        return mcs;
    }
	
    /**
     * 添加
     * @param columnName 列名
     * @return
     */
    public boolean add(String columnName)
    {
    	return add(columnName, Types.NVARCHAR, false, true, -1, false, null);
    }

    /**
     * 添加
     * @param columnName 列名
     * @param sqlType 数据库字段类型
     * @return
     */
    public boolean add(String columnName, int sqlType)
    {
    	return add(columnName, sqlType, false, true, -1, false, null);
    }

    /**
     * 添加
     * @param columnName 列名
     * @param sqlType 数据库字段类型
     * @param isAutoIncrement 是否自增ID列
     * @return
     */
    public boolean add(String columnName, int sqlType, boolean isAutoIncrement)
    {
    	return add(columnName, sqlType, isAutoIncrement, !isAutoIncrement, -1, isAutoIncrement, null);
    }

    /**
     * 添加
     * @param columnName 列名
     * @param sqlType 数据库字段类型
     * @param isAutoIncrement 是否自增ID列
     * @param isCanNull
     * @param maxSize
     * @return
     */
    public boolean add(String columnName, int sqlType, boolean isAutoIncrement, boolean isCanNull, int maxSize)
    {
    	return add(columnName, sqlType, isAutoIncrement, isCanNull, maxSize, false, null);
    }
	
    public boolean add(String columnName, int sqlType, boolean isAutoIncrement, boolean isCanNull, int maxSize, boolean isPrimaryKey, Object defaultValue)
    {
    	boolean addSuccess = false;
        String[] items = StringUtils.split(columnName,',');
        for (String item : items)
        {
            MCellStruct mdcStruct = new MCellStruct(item, sqlType, isAutoIncrement, isCanNull, maxSize);
            mdcStruct.setPrimaryKey(isPrimaryKey);
            mdcStruct.setDefaultValue(defaultValue);
            addSuccess = add(mdcStruct);
        }
        return addSuccess;
    }
	
	public boolean add(MCellStruct struct) {
        boolean addSuccess = false;
		if (struct != null && !this.contains(struct) && (!checkDuplicate || !contains(struct.getColumnName())))
        {
            if (dbType == DBType.NONE)
            {
                dbType = struct.getDbType();
            }
            struct.setmDataColumn(this);
            addSuccess = structList.add(struct);
            if (table != null && table.getRows().size() > 0)
            {
                for (int i = 0; i < table.getRows().size(); i++)
                {
                    if (size() > table.getRows().get(i).size())
                    {
                    	table.getRows().get(i).add(new MDataCell(struct));
                    }
                }
            }
            columnIndex.clear();
        }
		return addSuccess;
	}
	
	@Override
	public void add(int index, MCellStruct element) {
		structList.add(index,element);
	}

	@Override
	public boolean addAll(Collection<? extends MCellStruct> c) {
		// TODO Auto-generated method stub
		return structList.addAll(c);
	}

	@Override
	public boolean addAll(int index, Collection<? extends MCellStruct> c) {
		// TODO Auto-generated method stub
		return structList.addAll(index, c);
	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub
		structList.clear();
	}

	/**
	 * 只能是列名
	 * @param columnName
	 * @return
	 */
	@Override
	public boolean contains(Object columnName) {
		if(columnName instanceof String){
			return indexOf(columnName)>-1;
		}else{
			return false;
		}	
	}
	
	@Override
	public boolean containsAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return structList.containsAll(c);
	}

	@Override
	public MCellStruct get(int index) {
		return structList.get(index);
	}

	@Override
	public int indexOf(Object columnName) {
		if(!(columnName instanceof String)) return -1;
		String colName = String.valueOf(columnName);
		if(columnIndex.size() == 0 || isColumnNameChanged || columnIndex.size() != structList.size()){
			columnIndex.clear();
			for (int i = 0; i < structList.size(); i++) {
				columnIndex.put(this.get(i).getColumnName().replace("_", ""), i);
			}
			isColumnNameChanged = false;
		}
		
		if(StringUtils.isNotEmpty(colName)){
			if(colName.indexOf('_')>-1){
				colName = colName.replace("_", "");				
			}
			if(columnIndex.containsKey(colName)){
				return columnIndex.get(colName);
			}
		}
		return -1;
	}
	
	@Override
	public boolean isEmpty() {
		// TODO Auto-generated method stub
		return structList.isEmpty();
	}

	@Override
	public Iterator<MCellStruct> iterator() {
		// TODO Auto-generated method stub
		return structList.iterator();
	}

	@Override
	public int lastIndexOf(Object o) {
		// TODO Auto-generated method stub
		return structList.lastIndexOf(o);
	}

	@Override
	public ListIterator<MCellStruct> listIterator() {
		// TODO Auto-generated method stub
		return structList.listIterator();
	}

	@Override
	public ListIterator<MCellStruct> listIterator(int index) {
		// TODO Auto-generated method stub
		return structList.listIterator(index);
	}

	@Override
	public boolean remove(Object o) {
		// TODO Auto-generated method stub
		return structList.remove(o);
	}

	@Override
	public MCellStruct remove(int index) {
		// TODO Auto-generated method stub
		return structList.remove(index);
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return structList.removeAll(c);
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		// TODO Auto-generated method stub
		return structList.retainAll(c);
	}

	@Override
	public MCellStruct set(int index, MCellStruct element) {
		// TODO Auto-generated method stub
		return structList.set(index, element);
	}

	@Override
	public int size() {
		return structList.size();
	}

	@Override
	public List<MCellStruct> subList(int fromIndex, int toIndex) {
		// TODO Auto-generated method stub
		return structList.subList(fromIndex, toIndex);
	}

	@Override
	public Object[] toArray() {
		// TODO Auto-generated method stub
		return structList.toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		// TODO Auto-generated method stub
		return structList.toArray(a);
	}
	
}
